//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<SplashScreen.cpp>
///	@path	~/src/appear/ui/
///	@date	2007/07/03
///	@desc	Splash screen base class.

#include "config/config.h"

#include "lib/utilities/string.h"
#include "lib/utilities/debug.h"

#include "appear/xwin/SplashScreen.h"

// close splash screen command
#define	CLOSE_WPARAM		(0x1234)
#define	CLOSE_LPARAM		(0x8888)

namespace xeres {

	// ctor
	SplashScreen::SplashScreen( void )
		: m_hWnd( NULL )
		, m_progress( 0 )
	{}

	// dtor
	SplashScreen::~SplashScreen( void )
	{}

	// win proc for splash sceen window
	LRESULT CALLBACK SplashSceenProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
	{
		TRACK_FUNCTION_SCOPE();

		switch( msg )
		{
		case WM_ERASEBKGND: // we won't erase background
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc( hWnd , msg , wParam , lParam );
		}
		return 0;
	}

	// we process all messages here
	void SplashScreen::ShowLoading( HWND hScreenWnd , int width , int height )
	{
		TRACK_FUNCTION_SCOPE();

		m_hWnd = hScreenWnd;

		// setup windows to be the one we want

		// first we hide the window
		::ShowWindow( hScreenWnd , SW_HIDE );

		// set window title
		::SetWindowText( hScreenWnd , m_title.c_str() );

		// redirect window proc
		WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr( hScreenWnd , GWLP_WNDPROC );
		::SetWindowLongPtr( hScreenWnd , GWLP_WNDPROC , (LONG_PTR)SplashSceenProc );

		// set window style to border-less pop-up
		::SetWindowLongPtr( hScreenWnd , GWL_STYLE , WS_POPUP );

		// set position & size
		const int screenWidth = ::GetSystemMetrics( SM_CXSCREEN );
		const int screenHeight = ::GetSystemMetrics( SM_CYSCREEN );
		const int positionX = ( screenWidth - width ) / 2;
		const int positionY = ( screenHeight - height ) / 2;
		::MoveWindow( hScreenWnd , positionX , positionY , width , height , TRUE );

		// FIXME: set layered window if needed

		// call prepare
		OnPrepare();

		// show & update window
		::ShowWindow( hScreenWnd , SW_SHOW );
		::UpdateWindow( hScreenWnd );

		::InvalidateRect( hScreenWnd , NULL , TRUE );

		MSG msg;
		BOOL bRet;
		bool running = true;
		while( running &&
			( ( bRet = ::GetMessage( &msg , hScreenWnd , 0 , 0 ) ) != 0 ) )
		{
			if( bRet == -1 )
			{
				// there maybe some error
				return;
			}
			switch( msg.message )
			{
			case WM_PAINT:
				// call on draw
				OnDraw();
				break;
			case WM_COMMAND:
				// filter close splash screen command
				if( msg.wParam == CLOSE_WPARAM && msg.lParam == CLOSE_LPARAM )
				{
					m_hWnd = NULL;
					running = false;
				}
				break;
			case WM_CLOSE:
				// FIXME: should query close from caller
			default:
				::TranslateMessage(&msg);
				::DispatchMessage(&msg);
			}
		}

		// call close
		OnClose();

		// restore window
		::SetWindowLongPtr( hScreenWnd , GWLP_WNDPROC , (LONG_PTR)oldProc );

		// hide it
		::ShowWindow( hScreenWnd , SW_HIDE );
	}

	// call to close splash screen
	void SplashScreen::Close( void )
	{
		::PostMessage( GetWindow() , WM_COMMAND , CLOSE_WPARAM , CLOSE_LPARAM );
	}

	// set window title
	void SplashScreen::SetTitle( const WString& title )
	{
		if( m_title != title )
		{
			m_title = title;
			if( m_hWnd != NULL )
			{
				::SetWindowText( m_hWnd , m_title.c_str() );
			}
		}
	}

	// set cue info
	void SplashScreen::SetCue( const WString& cue )
	{
		if( m_cue != cue )
		{
			m_cue = cue;
			if( m_hWnd != NULL )
			{
				::InvalidateRect( m_hWnd , NULL , FALSE );
			}
		}
	}

	// set progress
	void SplashScreen::SetProgress( int progress )
	{
		if( m_progress != progress )
		{
			m_progress = max( 0 , min( progress , 100 ) );
			if( m_hWnd != NULL )
			{
				::InvalidateRect( m_hWnd , NULL , FALSE );
			}
		}
	}

	// ctor
	DefaultSplashScreen::DefaultSplashScreen( void )
		: m_backgroundBrush( NULL )
		, m_loadingBrush( NULL )
		, m_loadingBackground( NULL )
		, m_textFont( NULL )
		, m_cueFont( NULL )
	{
	}

	// on prepare
	void DefaultSplashScreen::OnPrepare( void )
	{
		m_backgroundBrush = ::CreateSolidBrush( RGB( 66 , 66 , 66 ) );
		m_loadingBackground = ::CreateSolidBrush( RGB( 33 , 33 , 33 ) );
		m_loadingBrush = ::CreateSolidBrush( RGB( 12 , 12 , 12 ) );

		LOGFONT lft , lfc;
		lft.lfHeight = 40;
		lft.lfWidth = 16;
		lft.lfEscapement = 900;
		lft.lfOrientation = 900;
		lft.lfWeight = FW_NORMAL;
		lft.lfItalic = FALSE;
		lft.lfUnderline = FALSE;
		lft.lfStrikeOut = FALSE;
		lft.lfCharSet = ANSI_CHARSET;
		lft.lfOutPrecision = OUT_DEFAULT_PRECIS;
		lft.lfClipPrecision = CLIP_STROKE_PRECIS | CLIP_LH_ANGLES;
		lft.lfQuality = CLEARTYPE_NATURAL_QUALITY;
		lft.lfPitchAndFamily = DEFAULT_PITCH;
		wcscpy( lft.lfFaceName , _S("Arial") );

		memcpy( &lfc , &lft , sizeof(LOGFONT) );
		lfc.lfEscapement = 0;
		lfc.lfOrientation = 0;
		lfc.lfHeight = 14;
		lfc.lfWidth = 5;
		wcscpy( lfc.lfFaceName , _S("Tahoma") );

		m_textFont = ::CreateFontIndirect( &lft );
		m_cueFont = ::CreateFontIndirect( &lfc );
	}

	// on draw
	void DefaultSplashScreen::OnDraw( void )
	{
		TRACK_FUNCTION_SCOPE();

		static const WString __xeresVersionInfo =
			_S("XERES engine");

		// prepare drawing resources
		HWND hWnd = GetWindow();
		PAINTSTRUCT ps;
		memset( &ps , 0 , sizeof(ps) );
		::BeginPaint( hWnd , &ps );
		
		RECT rect;
		::GetClientRect( hWnd , &rect );

		RECT rectText = rect;
		rectText.left += 10;
		rectText.top = rect.bottom - 30;

		::FillRect( ps.hdc , &rect , m_backgroundBrush );

		::SetBkMode( ps.hdc , TRANSPARENT );
		::SetTextColor( ps.hdc , RGB(233,233,233) );
		::SelectObject( ps.hdc , m_textFont );
		::DrawText( ps.hdc , __xeresVersionInfo.c_str() , (int)__xeresVersionInfo.size() ,
			&rectText , DT_LEFT | DT_NOCLIP );

		RECT rectLd = rect;
		rectLd.top = rect.bottom - 10;
		::FillRect( ps.hdc , &rectLd , m_loadingBackground );

		if( GetProgress() > 0 )
		{
			float percent = GetProgress() / 100.f;
			rectLd.right = (int)( (float)( rect.right - rect.left ) * percent );
			// draw loading text
			::FillRect( ps.hdc , &rectLd , m_loadingBrush );
		}

		// draw cue
		RECT rectCue = rect;
		rectCue.top = rect.bottom - 27;
		rectCue.right -= 5;

		::SetTextColor( ps.hdc , RGB(190,190,190) );
		::SelectObject( ps.hdc  , m_cueFont );
		::DrawText( ps.hdc , GetCue().c_str() , (int)GetCue().size() ,
			&rectCue , DT_RIGHT | DT_NOCLIP );

		// clean up
		::EndPaint( hWnd , &ps );
	}

	// call to close window, clean up resources
	void DefaultSplashScreen::OnClose( void )
	{
		::DeleteObject( m_backgroundBrush );
		::DeleteObject( m_loadingBrush );
		::DeleteObject( m_loadingBackground );
		::DeleteObject( m_textFont );
		::DeleteObject( m_cueFont );
	}

} // namespace xeres
